package cn.jdy.task.service;

import cn.jdy.common.util.ClassUtil;
import cn.jdy.framework.db.hibernate.BaseDao;
import cn.jdy.framework.log.BaseLog;
import cn.jdy.task.entity.SchedulingJob;

import org.hibernate.Transaction;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.quartz.CronScheduleBuilder;
import org.quartz.Job;
import org.quartz.JobBuilder;
import org.quartz.JobDataMap;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.ScheduleBuilder;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service("schedulerService")
public class SchedulerService extends BaseDao<SchedulingJob> {

	@Autowired
	private Scheduler scheduler;

	public static Map<String, String> jobGroupMap;
	static {
		jobGroupMap = new HashMap<String, String>();
		BaseLog.i(SchedulerService.class, SchedulerService.class.getPackage().getName() + ".classify");
		List<Class<?>> classList = ClassUtil.getClasses(SchedulerService.class.getPackage().getName() + ".classify");
		for(Class<?> clazz : classList) {
			TaskGroup taskGroup = clazz.getAnnotation(TaskGroup.class);
			if(taskGroup!=null) {
				Class<?>[] interfaces = clazz.getInterfaces();
				for(Class<?> c : interfaces) {
					BaseLog.i(SchedulerService.class, clazz.getName()+"    :    "+taskGroup.value());
					if(Job.class.equals(c)) {
						BaseLog.i(SchedulerService.class, "This is a Job"+clazz.getName()+"    :    "+taskGroup.value());
						jobGroupMap.put(clazz.getName(), taskGroup.value());
						break;
					}
				}
			}
		}
	}
	
	/**
	 * 根据条件查询定时任务
	 *
	 * @param entity
	 * @return
	 */
	public List<SchedulingJob> queryTimers(SchedulingJob entity, String... date) {
		DetachedCriteria dc = DetachedCriteria.forClass(super.entityClass);
		if(date.length>0 && date[0]!=null) {
			date[1] = date[1] + "23:59:59";
			dc.add(Restrictions.between("orderDate", date[0], date[1]));
		}
		if(entity.getJobName()!=null && entity.getJobName().length()>0)
			dc.add(Restrictions.eq("jobName", entity.getJobName()));
		if(entity.getJobGroup()!=null && entity.getJobGroup().length()>0)
			dc.add(Restrictions.eq("jobGroup", entity.getJobGroup()));
		dc.addOrder(Order.asc("jobGroup"));
		dc.addOrder(Order.desc("id"));
		return super.find(dc, entity.getiDisplayStart(), entity.getiDisplayLength());
	}

	/**
	 * 查询指定条件的记录数
	 *
	 * @param entity
	 * @return
	 */
	public Long count(SchedulingJob entity, String... date) {
		DetachedCriteria dc = DetachedCriteria.forClass(super.entityClass);
		if(date.length>0 && date[0]!=null) {
			date[1] = date[1] + "23:59:59";
			dc.add(Restrictions.between("orderDate", date[0], date[1]));
		}
		if(entity.getJobName()!=null && entity.getJobName().length()>0)
			dc.add(Restrictions.eq("jobName", entity.getJobName()));
		if(entity.getJobGroup()!=null && entity.getJobGroup().length()>0)
			dc.add(Restrictions.eq("jobGroup", entity.getJobGroup()));
		return super.count(dc);
	}


	/**
	 * 查询定时任务
	 * @param isByTrigger
	 * @return
	 * @throws SchedulerException
	 */
	public List<SchedulingJob> queryAll(boolean isByTrigger) throws SchedulerException {
		/*List<SchedulingJob> list = new LinkedList<SchedulingJob>();//scheduler.getJobGroupNames();
		GroupMatcher paramGroupMatcher = isByTrigger?GroupMatcher.anyTriggerGroup():GroupMatcher.anyJobGroup();
		Set<? extends Key> set = isByTrigger?scheduler.getTriggerKeys(paramGroupMatcher):scheduler.getJobKeys(paramGroupMatcher);
		if(isByTrigger) {
			for(Key<TriggerKey> key : set)
				list.add((SchedulingJob)scheduler.getJobDetail(scheduler.getTrigger((TriggerKey)key).getJobKey()).getJobDataMap().get("schedulingJob"));
		}else {
			for(Key<JobKey> key : set)
				list.add((SchedulingJob)scheduler.getJobDetail((JobKey)key).getJobDataMap().get("schedulingJob"));
		}*/
		return super.find();
	}
	
	/**
	 * 手动触发一次任务
	 * @param schedulingJob
	 * @throws SchedulerException
	 */
	public void triggerJob(SchedulingJob schedulingJob) throws SchedulerException {
		JobDataMap jobDataMap = new JobDataMap();
		jobDataMap.put("date", schedulingJob.getStrParam2());
		jobDataMap.put("strParam", schedulingJob.getStrParam());
		schedulingJob = super.find(schedulingJob.getId());
		scheduler.triggerJob(new JobKey(schedulingJob.getJobName(), schedulingJob.getJobGroup()), jobDataMap);
	}

	/**
	 * 新建或者更新一个定时任务
	 * @throws java.sql.SQLException
	 * @throws SchedulerException
	 * @throws ClassNotFoundException 
	 */
	@SuppressWarnings("unchecked")
	@Transactional
	public synchronized void saveOrUpd(SchedulingJob schedulingJob) throws SchedulerException, ClassNotFoundException {
		if(schedulingJob.getId()!=null) {
			super.update(schedulingJob);
			schedulingJob = super.find(schedulingJob.getId());
			TriggerKey tiggerKey = TriggerKey.triggerKey(schedulingJob.getJobName(), schedulingJob.getJobGroup());
			Trigger trigger = scheduler.getTrigger(tiggerKey);
			scheduler.getJobDetail(scheduler.getTrigger(tiggerKey).getJobKey()).getJobDataMap().put("strParam", schedulingJob.getStrParam());
			scheduler.rescheduleJob(tiggerKey, trigger.getTriggerBuilder().withSchedule((ScheduleBuilder)CronScheduleBuilder.cronSchedule(schedulingJob.getCronExpression())).usingJobData("strParam", schedulingJob.getStrParam()).build());
		}else {
			//设置入参
			JobDataMap jobDataMap = new JobDataMap();
			jobDataMap.put("strParam", schedulingJob.getStrParam());
			
			JobDetail jobDetail = JobBuilder.newJob((Class<? extends Job>)Class.forName(schedulingJob.getJobGroup())).withIdentity(schedulingJob.getJobName(), schedulingJob.getJobGroup()).setJobData(jobDataMap).build();
			Trigger trigger = TriggerBuilder.newTrigger().withIdentity(TriggerKey.triggerKey(schedulingJob.getJobName(), schedulingJob.getJobGroup())).withSchedule(CronScheduleBuilder.cronSchedule(schedulingJob.getCronExpression())).usingJobData(jobDataMap).build();
			scheduler.scheduleJob(jobDetail, trigger);

			schedulingJob.setStatus(SchedulingJob.JS_ENABLED);
			super.save(schedulingJob);
		}
		if(scheduler.isShutdown())
			scheduler.start();
	}

	public synchronized void startJob(SchedulingJob schedulingJob) throws ClassNotFoundException, SchedulerException {
		JobDataMap jobDataMap = new JobDataMap();
		jobDataMap.put("strParam", schedulingJob.getStrParam());

		TriggerKey tiggerKey = TriggerKey.triggerKey(schedulingJob.getJobName(), schedulingJob.getJobGroup());
		JobDetail jobDetail = JobBuilder.newJob((Class<? extends Job>) Class.forName(schedulingJob.getJobGroup())).withIdentity(schedulingJob.getJobName(), schedulingJob.getJobGroup()).setJobData(jobDataMap).build();
		Trigger trigger = TriggerBuilder.newTrigger().withIdentity(tiggerKey).withSchedule(CronScheduleBuilder.cronSchedule(schedulingJob.getCronExpression())).usingJobData(jobDataMap).build();
		scheduler.scheduleJob(jobDetail, trigger);
	}

	/**
	 * 删除一个任务
	 * @throws SchedulerException
	 */
	public synchronized void delete(Long id) throws SchedulerException {
		SchedulingJob schedulingJob = super.find(id);
		TriggerKey triggerKey = TriggerKey.triggerKey(schedulingJob.getJobName(), schedulingJob.getJobGroup());
		scheduler.pauseTrigger(triggerKey);//停止触发器
		scheduler.unscheduleJob(triggerKey);//移除触发器
		scheduler.deleteJob(JobKey.jobKey(schedulingJob.getJobName(), schedulingJob.getJobGroup()));//删除任务
		super.delete(id);
	}
	
	/**
	 * 暂停一个任务
	 * @throws SchedulerException
	 */
	public void pauseJob(String... names)
			throws SchedulerException {
		scheduler.pauseJob(JobKey.jobKey(names[0], names[1]==null?null:names[1]));
	}
	
	/**
	 * 继续执行一个任务
	 * @throws SchedulerException
	 */
	public void resumeJob(String... names)
			throws SchedulerException {
		scheduler.resumeJob(JobKey.jobKey(names[0], names[1]==null?null:names[1]));
	}
	
	/**
	 * 暂停一个定时器
	 * @throws SchedulerException
	 */
	public void pauseTrigger(String... names)
			throws SchedulerException {
		scheduler.pauseTrigger(TriggerKey.triggerKey(names[0], names[1]==null?null:names[1]));
	}
	
	/**
	 * 继续执行一个定时器
	 * @throws SchedulerException
	 */
	public void resumeTrigger(String... names)
			throws SchedulerException {
		scheduler.resumeTrigger(TriggerKey.triggerKey(names[0], names[1]==null?null:names[1]));
	}

}
